﻿#include "OiPCH.hpp"
#include "View/OiPixmap.hpp"

namespace Oi
{
    namespace PLScannerCore
    {
        class RotateDataImpl : public Impl<RotateData>
        {
        public:
            void init();
            void exit();

        public:
            double _pos;
            double _rangeMin;
            double _rangeMax;
        };

        void RotateDataImpl::init()
        {
            OI_Q(RotateData);

            View::Layer* dynamicLayer = NULL;
            auto pixmap = ImageViewer::OiImageViewer()->pixmap()->pixmap();
            auto pointMap = ImageViewer::OiImageViewer()->pointMap();
            auto rangeMap = ImageViewer::OiImageViewer()->rangeMap();
            auto pointMat = ImageViewer::OiImageViewer()->pointRemapMat();

            if (pointMap.isNull() && pointMat.empty() && rangeMap.isNull() && pixmap.isNull())
            {
                q->deleteLater();
                return;
            }
            if (ImageViewer::OiImageViewer())
            {
                dynamicLayer = ImageViewer::OiImageViewer()->dynamicLayer();
            }

            if (dynamicLayer)
            {
                q->setParentItem(dynamicLayer);
            }

            q->setZValue(50);

            _rangeMin = ImageViewer::OiImageViewer()->imageRect().left();
            _rangeMax = ImageViewer::OiImageViewer()->imageRect().right();

            _pos = _rangeMax;
        }

        void RotateDataImpl::exit()
        {
        }
      

        RotateData::RotateData()
        {
            OI_I(RotateData)->init();
           
        }

        RotateData::~RotateData()
        {
            OI_E(RotateData)->exit();
        }


        void RotateData::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
        {
            OI_F(RotateData);
            auto rect = ImageViewer::OiImageViewer()->imageRect();
            auto rect1 = ImageViewer::OiImageViewer()->imageRect();

            rect.setLeft(d->_pos);
            rect1.setRight(d->_pos);
            auto sp = rect.topLeft();
            auto ep = rect.bottomRight();
            auto sp1 = rect1.topLeft();
            auto ep1 = rect1.bottomRight();


            auto transform = painter->transform();
            painter->save();
            painter->setPen(Qt::NoPen);
            painter->translate(sp);
            painter->scale(1.0 / transform.m11(), 1.0 / transform.m22());
            painter->fillRect(0, 0, (ep.x() - sp.x()) * transform.m11(), (ep.y() - sp.y()) * transform.m22(), QBrush(QColor(255,255,255,20), Qt::SolidPattern));
            painter->restore();
            painter->save();
            painter->setPen(Qt::NoPen);
            painter->translate(sp1);
            painter->scale(1.0 / transform.m11(), 1.0 / transform.m22());
            painter->translate(sp1);
            painter->fillRect(0, 0, (ep1.x() - sp1.x()) * transform.m11(), (ep1.y() - sp1.y()) * transform.m22(), QBrush(QColor(0, 0, 0, 20), Qt::SolidPattern));
            painter->restore();
        }

        void RotateData::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
        {
            OI_F(RotateData);
            auto pos = mapToScene(event->pos());

            d->_pos = pos.x();

            if (pos.x() < d->_rangeMin) d->_pos = d->_rangeMin;
            if (pos.x() >= d->_rangeMax) d->_pos = d->_rangeMax;

            invalidate();
        }

        void RotateData::mousePressEvent(QGraphicsSceneMouseEvent *event)
        {
            OI_F(RotateData);
            if (event->button() == Qt::LeftButton)
            {
                auto pixmap = ImageViewer::OiImageViewer()->pixmap()->pixmap();
                auto pointMap = ImageViewer::OiImageViewer()->pointMap();
                auto rangeMap = ImageViewer::OiImageViewer()->rangeMap();
                auto pointMat = ImageViewer::OiImageViewer()->pointRemapMat();

                if (!pointMap.isNull() && !pointMat.empty())
                {
                    int l = d->_pos - d->_rangeMin + 0.5;
                    auto point1 = Core::PointMap::create(pointMap->cols(), pointMap->count());
                    point1->resize(pointMap->count());
                    for (int i = 0; i < pointMap->count(); i++)
                    {
                        auto pz = pointMap->zLine((l + i) % pointMap->count());
                        auto px = pointMap->xLine((l + i) % pointMap->count());
                        auto py = pointMap->yLine((l + i) % pointMap->count());
                        auto pz1 = point1->zLine(i);
                        auto px1 = point1->xLine(i);
                        auto py1 = point1->yLine(i);
                        memcpy(pz1, pz, pointMap->cols() * sizeof(float));
                        memcpy(px1, px, pointMap->cols() * sizeof(float));
                        memcpy(py1, py, pointMap->cols() * sizeof(float));

                    }

                    ImageViewer::OiImageViewer()->display(point1);
                }
                else if (!rangeMap.isNull())
                {
                    int l = d->_pos - d->_rangeMin + 0.5;
                    auto range1 = Core::RangeMap::create(rangeMap->cols(), rangeMap->count());
                    for (int i = 0; i < rangeMap->count(); ++i)
                    {
                        auto ran = rangeMap->profile((l + i) % rangeMap->count());
                        auto ran1 = range1->newProfile();
                        memcpy(ran1, ran, rangeMap->cols() * sizeof(float));
                    }
                    ImageViewer::OiImageViewer()->display(range1);
                }
                else if (!pixmap.isNull())
                {
                    int l = d->_pos - d->_rangeMin + 0.5;
                    int l1 = d->_rangeMax - d->_pos + 0.5;
                    QImage rightimg = pixmap.copy(0, 0, pixmap.width(), l);
                    QImage leftimg = pixmap.copy(0, l, pixmap.width(), l1);
                    QImage resultimg(pixmap.width(),pixmap.height(),QImage::Format_RGB32);
                    QPainter* painter = new QPainter(&resultimg);
                    painter->drawImage(0,0,leftimg);
                    painter->drawImage(0,l1,rightimg);
                    ImageViewer::OiImageViewer()->display(resultimg);
                }
                else
                {
                    deleteLater();
                    return;
                }

                ImageViewer::OiImageViewer()->zoomFit();

            }
            else if (event->button() == Qt::RightButton) {
                ImageViewer::OiImageViewer()->blockContextMenuEvent();
                deleteLater();
                return;
            }

            __super::mousePressEvent(event);
        }

        void RotateData::autoRotateData()
        {
            int sampleNum = 20;
            int sampleWidth = 30;

            std::vector<cv::Mat_<float>> smats;

            auto pointMap = ImageViewer::OiImageViewer()->pointMap();
            auto rangeMap = ImageViewer::OiImageViewer()->rangeMap();
            auto pointMat = ImageViewer::OiImageViewer()->pointRemapMat();

            if(!pointMap.isNull() && !pointMat.empty())
            {
                int pr = pointMat.cols;
                int pf = sampleWidth;
                int pe = pr - sampleWidth;
                double sampleInterval = 1.0 * ( pe - pf ) / sampleNum;

                for (int i = 0; i < sampleNum; i++)
                {
                    smats.push_back(pointMat(cv::Range::all(), cv::Range(pf + i * sampleInterval, pf + i * sampleInterval + sampleWidth)));
                }
            }
            else if(!rangeMap.isNull())
            {
                int pr = rangeMap->cols();
                int pf = sampleWidth;
                int pe = pr - sampleWidth;
                double sampleInterval = 1.0 * ( pe - pf ) / sampleNum;

                for(int i = 0; i < sampleNum; i++)
                {
                    smats.push_back((*( cv::Mat_<float>* )( rangeMap->matrix() ) ) ( cv::Range::all(), cv::Range(pf + i * sampleInterval, pf + i * sampleInterval + sampleWidth)));
                }
            }

            if(smats.empty())
            {
                return;
            }

            std::vector<int> splicePoss;

            splicePoss.resize(smats.size());

            for (int i = 0; i < smats.size(); i++)
            {
                splicePoss[i] = -1;
            }

        #pragma omp parallel 
            {
            #pragma omp for 

                for(int s = 0; s < smats.size(); s++)
                {
                    cv::Mat_<float> line;
                    auto srcMat = smats[s];

                    Util::reduceAvg(smats[s], line, 1);

                    QList<int> cComositeIndex;
                    if(true)
                    {
                        for(int i = 1; i <= qMax(32, line.size[0] / 50); i++)
                        {
                            cComositeIndex << i;
                        }
                    }

                    cv::Mat_<float> amp;
                    cv::Mat_<float> phase;

                    if(Util::DFT_1D(line, amp, phase))
                    {
                        int maxAmpIndex = 1;
                        double maxAmp = 0.0;

                        for(int i = 1; i <= 10; i++)
                        {
                            if(amp( i, 0 ) > maxAmp)
                            {
                                maxAmp = amp( i, 0 );
                                maxAmpIndex = i;
                            }
                        }

                        float* ampD = ( float* )amp.data;
                        float* phaseD = (float*)phase.data;

                        double maxValue = 0.0;
                        double maxIndex = 0.0;
                        //画的标记线的前后端
                        double min = 0.0;
                        double max = 0.0;

                        cv::Mat_<float> ampcopy;
                        ampcopy = amp.clone();
                        for(int i = 0; i < amp.size[0]; i++)
                        {
                            float sum = 0.0;
                            for(int j : cComositeIndex)
                            {
                                if(ampD[j] > 0.001)
                                {
                                    sum += ampD[j] * cos(2 * M_PI*j*i / amp.size[0] + phaseD[j]);
                                }

                            }

                            ampcopy(i, 0) = -10 * sum;
                        }

                        cv::Mat_<float> tidu;
                        cv::Sobel(ampcopy, tidu, CV_32F, 0, 1, 3, 1.0, 0.0, cv::BORDER_REPLICATE);

                        double blockBorder = 0;

                        if(maxAmpIndex > 2)
                        {
                            blockBorder = tidu.size[0] / 4 / maxAmpIndex;
                        }

                        for(int i = blockBorder; i < tidu.size[0] - blockBorder; ++i)
                        {
                            if(fabs(tidu(i, 0)) > maxValue)
                            {
                                maxValue = fabs(tidu(i, 0));
                                maxIndex = i;
                            }
                        }
                            
                        if (maxValue > 0.0)
                        {
                            splicePoss[s] = maxIndex;
                        }
                    }
                }
            }

            if (splicePoss.size() < sampleNum / 5)
            {
                return;
            }

            for (auto iter = splicePoss.begin(); iter != splicePoss.end(); )
            {
                if (*iter < 0)
                {
                    iter = splicePoss.erase(iter);
                }
                else
                {
                    iter++;
                }
            }

            std::sort(std::begin(splicePoss), std::end(splicePoss));

            int midPos = splicePoss[splicePoss.size() / 2];

            auto pos = ImageViewer::OiImageViewer()->mapImageFromRulerPos(QPointF(PLScanner::instance()->autoRotateSplicePos, 0)).y();

            if(!pointMap.isNull() && !pointMat.empty())
            {
                int l = ( midPos - pos ) >= 0 ? midPos - pos : (pointMap->count() - midPos + pos);
                auto point1 = Core::PointMap::create(pointMap->cols(), pointMap->count());
                point1->resize(pointMap->count());
                for(int i = 0; i < pointMap->count(); i++)
                {
                    auto pz = pointMap->zLine(( l + i ) % pointMap->count());
                    auto px = pointMap->xLine(( l + i ) % pointMap->count());
                    auto py = pointMap->yLine(( l + i ) % pointMap->count());
                    auto pz1 = point1->zLine(i);
                    auto px1 = point1->xLine(i);
                    auto py1 = point1->yLine(i);
                    memcpy(pz1, pz, pointMap->cols() * sizeof(float));
                    memcpy(px1, px, pointMap->cols() * sizeof(float));
                    memcpy(py1, py, pointMap->cols() * sizeof(float));
                }

                ImageViewer::OiImageViewer()->display(point1);
            }
            else if(!rangeMap.isNull())
            {
                int l = ( midPos - pos ) >= 0 ? midPos - pos : (rangeMap->count() - midPos + pos);

                auto range1 = Core::RangeMap::create(rangeMap->cols(), rangeMap->count());
                for(int i = 0; i < rangeMap->count(); ++i)
                {
                    auto ran = rangeMap->profile(( l + i ) % rangeMap->count());
                    auto ran1 = range1->newProfile();
                    memcpy(ran1, ran, rangeMap->cols() * sizeof(float));
                }
                ImageViewer::OiImageViewer()->display(range1);
            }

        }

    }
}